package at.fhj.pse.domain.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.inject.Inject;

import at.fhj.pse.datasource.ActivityDAO;
import at.fhj.pse.datasource.TimeIntervalDAO;
import at.fhj.pse.datasource.exception.DatasourceLayerException;
import at.fhj.pse.datasource.model.Activity;
import at.fhj.pse.datasource.model.Employee;
import at.fhj.pse.datasource.model.TimeInterval;
import at.fhj.pse.domain.TimeIntervalBean;
import at.fhj.pse.domain.exception.DomainLayerException;
import at.fhj.pse.domain.exception.StacktraceToString;
import at.fhj.pse.domain.service.IntervalService;

@Stateless
@Local(TimeIntervalBean.class)
public class TimeIntervalBeanImpl implements Serializable, TimeIntervalBean {

	private final Logger LOG = Logger
			.getLogger(TimeIntervalBeanImpl.class.getName());
	
	@Inject
	private TimeIntervalDAO timeIntervalDao;

	@Inject
	private ActivityDAO activityDao;

	private static final long serialVersionUID = -476125696014965200L;

	@Override
	public List<TimeInterval> getIntervalsByDay(Date day, Employee employee) {
		if (day == null) {
			throw new DomainLayerException("day is null", new IllegalArgumentException());
		}
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		try {
			return this.timeIntervalDao.getTimeIntervalByDayAndUsername(day,
					employee.getUsername());
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public List<TimeInterval> getIntervalsByActivity(Activity activity,
			Date fromDate, Date toDate, Employee employee) {
		if (activity == null) {
			throw new DomainLayerException("activity is null", new IllegalArgumentException());
		}
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		try {
			return this.timeIntervalDao
					.getTimeIntervalByActivityAndDatesAndUsername(activity,
							fromDate, toDate, employee.getUsername());
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public List<TimeInterval> getIntervalsByDates(Date fromDate, Date toDate,
			Employee employee) {
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		try {
			return this.timeIntervalDao.getTimeIntervalByDatesAndUsername(fromDate,
					toDate, employee.getUsername());
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public List<String> getActivityNames() {
		try {
			List<Activity> activities = activityDao.getActivities();
			activities = this.activityDao.getActivities();
			List<String> activityNames = new ArrayList<String>();
			for (Activity activity : activities) {
				String description = activity.getDescription();
				activityNames.add(description);
			}
			return activityNames;
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public boolean validateToGreaterThanFrom(Date toDate, Date fromDate) {
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		if (toDate.getTime() <= fromDate.getTime())
			return false;
		return true;
	}

	@Override
	public boolean validateSameDay(Date toDate, Date fromDate) {
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(fromDate);

		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(toDate);
		if (cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public boolean intervalOverlap(Employee employee, Date toDate, Date fromDate) {
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		try {
			List<TimeInterval> til = timeIntervalDao
					.getTimeIntervalByDayAndUsername(fromDate,
							employee.getUsername());
			for (TimeInterval timeInterval : til) {
				if (timeInterval.getFrom().after(fromDate)
						&& timeInterval.getFrom().before(toDate)
						|| timeInterval.getTo().after(fromDate)
						&& timeInterval.getTo().before(toDate)
						|| timeInterval.getFrom().before(fromDate)
						&& timeInterval.getTo().after(toDate)
						|| timeInterval.getFrom().getTime() == fromDate.getTime()
						&& timeInterval.getTo().getTime() == toDate.getTime()) {
					return false;
				}
			}
			return true;
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public void addTimeInterval(Employee employee, Date toDate, Date fromDate,
			String comment, Activity tiActivity) {
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		if (comment == null) {
			throw new DomainLayerException("comment is null", new IllegalArgumentException());
		}
		if (tiActivity == null) {
			throw new DomainLayerException("tiActivity is null", new IllegalArgumentException());
		}
		TimeInterval ti = new TimeInterval();
		ti.setFrom(fromDate);
		ti.setTo(toDate);
		ti.setActivity(tiActivity);
		ti.setComment(comment);
		ti.setEmployee(employee);
		try {
			timeIntervalDao.saveTimeInterval(ti);
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public void deleteTimeIntervalById(long id) {
		try {
			timeIntervalDao.deleteTimeIntervalById(id);
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public List<TimeInterval> getAllEmployeeIntervals(long employeeId) {
		try {
			return this.timeIntervalDao.getTimeIntervalByEmployeeID(employeeId);
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public List<TimeInterval> loadAllEmployeeIntervals(long employeeId) {
		try {
			return timeIntervalDao.getTimeIntervalByEmployeeID(employeeId);
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public IntervalService getIntervalServiceByDay(Date day, Employee employee) {
		if (day == null) {
			throw new DomainLayerException("day is null", new IllegalArgumentException());
		}
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		try {
			return new IntervalService(this.getIntervalsByDay(day, employee), "day");
		} catch (DomainLayerException | DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public IntervalService getIntervalServiceByMonthAndYear(Employee employee,
			String month, int year) {
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		if (month == null) {
			throw new DomainLayerException("month is null", new IllegalArgumentException());
		}
		if (month != null && !month.equals("") && year != 0) {
			int monthInt = 0;
			switch (month) {
			case "January":
				monthInt = 1;
				break;
			case "February":
				monthInt = 2;
				break;
			case "March":
				monthInt = 3;
				break;
			case "April":
				monthInt = 4;
				break;
			case "May":
				monthInt = 5;
				break;
			case "June":
				monthInt = 6;
				break;
			case "July":
				monthInt = 7;
				break;
			case "August":
				monthInt = 8;
				break;
			case "September":
				monthInt = 9;
				break;
			case "October":
				monthInt = 10;
				break;
			case "November":
				monthInt = 11;
				break;
			case "December":
				monthInt = 12;
				break;
			}

			try {
				List<TimeInterval> intervals = this.timeIntervalDao
						.getTimeIntervalByMonthAndYearAndUsername(monthInt, year,
								employee.getUsername());
				return new IntervalService(intervals, "month");
			} catch (DomainLayerException | DatasourceLayerException ex) {
				LOG.warning(ex.getMessage());
				LOG.warning(StacktraceToString.build(ex));
				throw ex;
			}
		}
		return null;
	}

	@Override
	public IntervalService getIntervalServiceByActivity(Employee employee,
			Date toDate, Date fromDate, Activity tiActivity) {
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		if (tiActivity == null) {
			throw new DomainLayerException("tiActivity is null", new IllegalArgumentException());
		}
		try {
			return new IntervalService(this.getIntervalsByActivity(tiActivity,
					fromDate, toDate, employee), "interval");
		} catch (DomainLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public IntervalService getIntervalServiceByDates(Employee employee,
			Date toDate, Date fromDate) {
		if (employee == null) {
			throw new DomainLayerException("employee is null", new IllegalArgumentException());
		}
		if (fromDate == null) {
			throw new DomainLayerException("fromDate is null", new IllegalArgumentException());
		}
		if (toDate == null) {
			throw new DomainLayerException("toDate is null", new IllegalArgumentException());
		}
		try {
			return new IntervalService(this.getIntervalsByDates(fromDate, toDate,
					employee), "chart");
		} catch (DomainLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
	}

	@Override
	public Activity getActivityByName(String activityName) {
		if (activityName == null) {
			throw new DomainLayerException("activityName is null", new IllegalArgumentException());
		}
		try {
			List<Activity> activities = activityDao.getActivities();
			for (Activity activity : activities) {
				String description = activity.getDescription();
				if (activityName.equals(description)) {
					return activity;
				}
			}
		} catch (DatasourceLayerException ex) {
			LOG.warning(ex.getMessage());
			LOG.warning(StacktraceToString.build(ex));
			throw ex;
		}
		return null;
	}

}